package java5.io;

import java.util.Random;

public class UtilLoser implements Constantes {

    private int[][] linea = new int[50][4];
    private StringBuilder stb = new StringBuilder();
    private int[] c0;
    private int[] cx;
    private int[] cn;
    private int[] ck;
    private int[] cj;
    private int[] cc;
    private int[] _cj;

    private void inicializaOrdenadoresJaque() {
        if (_cj == null) {
            _cj = new int[]{0, 100, 200, 300, 400, 500, 600};
        } else {
            for (int i = 0; i < 7; i++) {
                _cj[i] = i * 100;
            }
        }
    }

    private void inicializaOrdenadoresCaptura() {
        if (cc == null) {
            cc = new int[]{0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500};
        } else {
            for (int i = 0; i < 11; i++) {
                cc[i] = i * 50;
            }
        }
    }

    private void inicializaOrdenadoresLocal() {
        if (c0 == null) {
            c0 = new int[]{0, 20, 40, 60, 80};
            cx = new int[]{100, 120, 140, 160, 180};
            cn = new int[]{200, 300, 400, 500, 600};
            ck = new int[]{700, 750};
            cj = new int[]{800, 820, 840, 860};
        } else {
            int t;
            for (int i = 0; i < 5; i++) {
                t = i * 20;
                c0[i] = t;
                cx[i] = 100 + t;
                cn[i] = 200 + i * 100;
                if (i < 2) {
                    ck[i] = 700 + i * 50;
                }
                if (i < 4) {
                    cj[i] = 800 + t;
                }
            }
        }
    }

    public int[] obtenerValoresPiezaXColor(int color) {
        switch (color) {
            case white:
                return new int[]{PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING};
            case black:
                return new int[]{pawn, knight, bishop, rook, queen, king};
        }
        return null;
    }

    public String imprimirTablero(int[] posiciones, boolean estavolteado) {

        StringBuilder tablero = new StringBuilder();
        String aux = "";
        int ficha, ind;

        for (int i = 0; i < 64; i++) {
            ind = estavolteado ? 63 - i : i;

            ficha = posiciones[ind];

            switch (ficha) {
                case vacio:
                    aux += "" + "|\t";
                    break;
                case PAWN:
                case pawn:
                    aux += (ficha == PAWN ? "P0" : "p1") + "|\t";
                    break;
                case KNIGHT:
                case knight:
                    aux += (ficha == KNIGHT ? "N" : "n") + "|\t";
                    break;
                case BISHOP:
                case bishop:
                    aux += (ficha == BISHOP ? "B" : "b") + "|\t";
                    break;
                case ROOK:
                case rook:
                    aux += (ficha == ROOK ? "R" : "r") + "|\t";
                    break;
                case QUEEN:
                case queen:
                    aux += (ficha == QUEEN ? "Q" : "q") + "|\t";
                    break;
                case KING:
                case king:
                    aux += (ficha == KING ? "K" : "k") + "|\t";
                    break;
            }
            if (estavolteado) {
                if (ind % 8 == 0) {
                    tablero.insert(0, (ind / 8 + 1) + "\t" + aux + "\n");
                    aux = "";
                }
            } else {
                if (ind != 0 && (ind + 1) % 8 == 0) {
                    tablero.insert(0, (ind / 8 + 1) + "\t" + aux + "\n");
                    aux = "";
                }
            }
        }

        if (estavolteado) {
            tablero.append("\t h \t g \t f \t e \t d \t c \t b \t a");
        } else {
            tablero.append("\t a \t b \t c \t d \t e \t f \t g \t h");
        }

        return tablero.toString();
    }

    public String imprimirTableroArray(int[] posiciones, boolean estavolteado) {

        StringBuilder tablero = new StringBuilder();
        String aux = "";
        int ficha, ind;

        for (int i = 0; i < 64; i++) {
            ind = estavolteado ? 63 - i : i;

            ficha = posiciones[ind];

            switch (ficha) {
                case vacio:
                    aux += "vacio" + ",";
                    break;
                case PAWN:
                case pawn:
                    aux += (ficha == PAWN ? "PAWN" : "pawn") + ",";
                    break;
                case KNIGHT:
                case knight:
                    aux += (ficha == KNIGHT ? "KNIGHT" : "knight") + ",";
                    break;
                case BISHOP:
                case bishop:
                    aux += (ficha == BISHOP ? "BISHOP" : "bishop") + ",";
                    break;
                case ROOK:
                case rook:
                    aux += (ficha == ROOK ? "ROOK" : "rook") + ",";
                    break;
                case QUEEN:
                case queen:
                    aux += (ficha == QUEEN ? "QUEEN" : "queen") + ",";
                    break;
                case KING:
                case king:
                    aux += (ficha == KING ? "KING" : "king") + ",";
                    break;
            }
            if (estavolteado) {
                if (ind % 8 == 0) {
                    tablero.insert(0, aux + "\n");
                    aux = "";
                }
            } else {
                if (ind != 0 && (ind + 1) % 8 == 0) {
                    tablero.insert(0, aux + "\n");
                    aux = "";
                }
            }
        }

        return tablero.toString();
    }

    public int esJaque(int[] amenazas) {
        int pos_jaque = -1;//-1=no hay jaque, 100=doble jaque, otro=pos jaque

        for (int i = 1; i < amenazas[0]; i++) {
            if (amenazas[i] > 99) {
                if (pos_jaque == -1) {
                    pos_jaque = amenazas[i] - 100;
                } else {
                    pos_jaque = 100;
                    break;
                }
            }
        }
        return pos_jaque;
    }

    public int esJaque(int[] amenazas, int pos_king) {
        int pos_jaque = -1;//-1=no hay jaque, 100=doble jaque, otro=pos jaque

        for (int i = 0; i < amenazas.length; i++) {
            if (amenazas[i] == pos_king) {
                if (pos_jaque == -1) {
                    pos_jaque = amenazas[i];
                } else {
                    pos_jaque = 100;
                    break;
                }
            }
        }
        return pos_jaque;
    }

    public int devuelvePosicionRey(int[] tablero, int color) {

        int bking = color == white ? KING : king;

        for (int j = 0; j < 64; j++) {
            if (tablero[j] == bking) {
                return j;
            }
        }

        return -1;
    }

    public String imprimirJugadas(int[][] jugadas) {

        stb.delete(0, stb.length());

        for (int i = 1; i < jugadas[0][0]; i++) {
            stb.append(this.imprimirJugada(jugadas[i])).append(",");
        }

        return stb.toString();
    }

    public String imprimirJugada(int[] j) {

        String strj = this.pos1(j[1]) + this.pos1(j[2]);

        if (j.length > 3) {
            switch (j[3]) {
                case KNIGHT:
                case knight:
                    strj += sKNIGHT;
                    break;
                case BISHOP:
                case bishop:
                    strj += sBISHOP;
                    break;
                case ROOK:
                case rook:
                    strj += sROOK;
                    break;
                case QUEEN:
                case queen:
                    strj += sQUEEN;
                    break;
            }
        }

        return strj;
    }

    public boolean enFila(int pos, int pos_king) {
        int f;
        for (int i = 0; i < 8; i++) {
            f = i * 8;
            if (pos >= f && pos < f + 8
                    && pos_king >= f && pos_king < f + 8) {
                return true;
            }
        }
        return false;
    }

    public boolean enColumna(int pos, int pos_king) {
        if (Math.abs(pos - pos_king) % 8 == 0) {
            return true;
        }
        return false;
    }

    public boolean siArrayContiene(int[] amenazas, int val) {
        for (int j = 1; j < amenazas[0]; j++) {
            if (amenazas[j] == val) {
                return true;
            }
        }
        return false;
    }

    private String pos1(int pos) {
        String str;

        if (pos < 8) {
            str = pos2(pos) + 1;
        } else {
            str = pos2(pos % 8) + (pos / 8 + 1);
        }

        return str;
    }

    private String pos2(int pos) {
        switch (pos) {
            case 0:
                return "a";
            case 1:
                return "b";
            case 2:
                return "c";
            case 3:
                return "d";
            case 4:
                return "e";
            case 5:
                return "f";
            case 6:
                return "g";
            case 7:
                return "h";
        }
        return "x";
    }

    public boolean estanEnDiagonal(int x, int y) {

        int factor = 1;
        int val;
        boolean a7 = true,
                b7 = true,
                a9 = true,
                b9 = true;
        do {
            if (a7) {
                val = x - (7 * factor);
                if (val % 8 > 0) {
                    if (val == y) {
                        return true;
                    }
                } else {
                    a7 = false;
                }
            }
            if (b7) {
                val = x + (7 * factor);
                if (val < 64 && val % 8 < 7) {
                    if (val == y) {
                        return true;
                    }
                } else {
                    b7 = false;
                }
            }
            if (a9) {
                val = x - (9 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (val == y) {
                        return true;
                    }
                } else {
                    a9 = false;
                }
            }
            if (b9) {
                val = x + (9 * factor);
                if (val < 64 && val % 8 > 0) {
                    if (val == y) {
                        return true;
                    }
                } else {
                    b9 = false;
                }
            }
            factor++;
        } while ((a7 || b7 || a9 || b9) && factor < 8);

        return false;
    }

    public int[] ingresarJugada(int[] tablero, int[] jugada, boolean esCopia) {

        int[] _tablero;
        int ficha = jugada[0];
        int ini = jugada[1];
        int fin = jugada[2];
        int prom = jugada[3];

        if (esCopia) {
            _tablero = new int[64];
            System.arraycopy(tablero, 0, _tablero, 0, 64);
        } else {
            _tablero = tablero;
        }

        if (ficha == pawn || ficha == PAWN) {
            if (fin > ini) {
                if (ini >= 32 && ini <= 39 && ini + 8 != fin && _tablero[fin] == vacio) {
                    _tablero[(fin - 8)] = vacio;
                }
            } else if (ini >= 24 && ini <= 31 && ini - 8 != fin && _tablero[fin] == vacio) {
                _tablero[(fin + 8)] = vacio;
            }
        } else if ((ficha == king || ficha == KING) && (ini == 4 || ini == 60)) {
            switch (fin) {
                case 2:
                    _tablero[3] = ROOK;
                    _tablero[0] = vacio;
                    break;
                case 6:
                    _tablero[5] = ROOK;
                    _tablero[7] = vacio;
                    break;
                case 58:
                    _tablero[59] = rook;
                    _tablero[56] = vacio;
                    break;
                case 62:
                    _tablero[61] = rook;
                    _tablero[63] = vacio;
            }
        }

        _tablero[fin] = (prom != 0 ? prom : _tablero[ini]);
        _tablero[ini] = vacio;

        return _tablero;
    }

    public boolean[] verificarEnroques(int ficha, int ini, boolean[] oo, boolean isWhite, boolean esCopia) {

        boolean[] enroques = null;

        if (oo[isWhite ? 0 : 2] || oo[isWhite ? 1 : 3]) {
            if (esCopia) {
                enroques = new boolean[4];
                System.arraycopy(oo, 0, enroques, 0, 4);
            } else {
                enroques = oo;
            }

            if (ficha == king || ficha == KING) {
                enroques[isWhite ? 0 : 2] = false;
                enroques[isWhite ? 1 : 3] = false;
            } else if (ficha == rook || ficha == ROOK) {
                switch (ini) {
                    case 0:
                    case 56:
                        enroques[isWhite ? 1 : 3] = false;
                        break;
                    case 7:
                    case 63:
                        enroques[isWhite ? 0 : 2] = false;
                        break;
                }
            }
        }

        return enroques == null ? oo : enroques;
    }

    public String convertirJugada(String j) {

        char[] c = j.toCharArray();

        return convnum(new char[]{c[0], c[1]}) + "," + convnum(new char[]{c[2], c[3]});
    }

    public int convnum(char[] c) {
        switch (c[0]) {
            case 'a':
                return 8 * (Character.getNumericValue(c[1]) - 1);
            case 'b':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 1;
            case 'c':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 2;
            case 'd':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 3;
            case 'e':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 4;
            case 'f':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 5;
            case 'g':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 6;
            case 'h':
                return 8 * (Character.getNumericValue(c[1]) - 1) + 7;
        }
        return -1;
    }

    public int valorarTableroDefensivo(int[] t, int color) {
        int valor = 0;
        int peones = 0;
        int ficha;

        if (color == white) {
            for (int i = 0; i < 64; i++) {
                ficha = t[i];
                if (ficha < 0) {
                    valor = valor + 1;
                    if (ficha == PAWN) {
                        peones = peones + 1;
                    }
                }
            }
        } else {
            for (int i = 0; i < 64; i++) {
                ficha = t[i];
                if (ficha > 0) {
                    valor = valor + 1;
                    if (ficha == pawn) {
                        peones = peones + 1;
                    }
                }
            }
        }

        //validando que quede al menos un peón
        if (peones == 0) {
            valor = -1;
        }

        return valor;
    }

    public int valorarTableroAgresivo(int[] t, int color) {
        int valor = 0;

        if (color == white) {
            for (int i = 0; i < 64; i++) {
                if (t[i] < 0) {
                    valor++;
                }
            }
        } else {
            for (int i = 0; i < 64; i++) {
                if (t[i] > 0) {
                    valor++;
                }
            }
        }

        return valor;
    }

    public boolean valorarTableroCompleto(int[] t) {
        int w = 0;
        int b = 0;
        int ficha;

        for (int i = 0; i < 64; i++) {
            ficha = t[i];
            if (ficha < 0) {
                w++;
            } else if (ficha > 0) {
                b++;
            }
        }

        return w < 10 || b < 10 ? true : false;
    }

    public int[][] ordenarMisJugadas(int[][] jugadas, int[] tablero) {

        int size = jugadas[0][0];
        int[] nuevasJugadas = new int[size - 1];
        int[][] ordenadas = new int[size - 1][4];

        int ficha;
        int c = 0;
        int[] j;

        if (jugadas[_cabeceraJugadas][_tieneJugadasObligatorias] == 1) {
            int[] o1 = new int[]{0, 10, 20, 30, 40};
            int fin;

            for (int i = 1; i < size; i++) {
                j = jugadas[i];
                fin = j[2];
                switch (tablero[fin]) {
                    case vacio:
                    case PAWN:
                    case pawn:
                        nuevasJugadas[c++] = o1[4]++;
                        break;
                    case KNIGHT:
                    case knight:
                        nuevasJugadas[c++] = o1[3]++;
                        break;
                    case BISHOP:
                    case bishop:
                        nuevasJugadas[c++] = o1[2]++;
                        break;
                    case ROOK:
                    case rook:
                        nuevasJugadas[c++] = o1[1]++;
                        break;
                    case QUEEN:
                    case queen:
                        nuevasJugadas[c++] = o1[0]++;
                        break;
                }
            }

            int _lim;
            int p, q;
            c = 0;

            for (p = 0; p < 50; p = p + 10) {
                _lim = o1[p / 10] - p;
                for (q = 0; q < _lim; q++) {
                    this.copiarArrayJugada(ordenadas[c++], jugadas[this.obtenerIndiceJugadaXOrden(nuevasJugadas, p + q, size - 1) + 1]);
                }
            }
        } else {
            int[] o2 = new int[]{0, 100, 200, 300, 400, 500};

            for (int i = 1; i < size; i++) {
                j = jugadas[i];
                ficha = j[0];

                switch (ficha) {
                    case PAWN:
                    case pawn:
                        nuevasJugadas[c++] = o2[0]++;
                        break;
                    case KNIGHT:
                    case knight:
                        nuevasJugadas[c++] = o2[1]++;
                        break;
                    case KING:
                    case king:
                        nuevasJugadas[c++] = o2[2]++;
                        break;
                    case BISHOP:
                    case bishop:
                        nuevasJugadas[c++] = o2[3]++;
                        break;
                    case QUEEN:
                    case queen:
                        nuevasJugadas[c++] = o2[4]++;
                        break;
                    case ROOK:
                    case rook:
                        nuevasJugadas[c++] = o2[5]++;
                        break;
                }
            }

            int _lim;
            int p, q;
            c = 0;

            for (p = 0; p < 600; p = p + 100) {
                _lim = o2[p / 100] - p;
                for (q = 0; q < _lim; q++) {
                    this.copiarArrayJugada(ordenadas[c++], jugadas[this.obtenerIndiceJugadaXOrden(nuevasJugadas, p + q, size - 1) + 1]);
                }
            }

            this.shufflePeones(ordenadas, o2[0]);
        }

        return ordenadas;
    }

    private void shufflePeones(int[][] ar, int lim) {
        Random rnd = new Random();
        for (int i = lim - 1; i >= 0; i--) {
            int index = rnd.nextInt(i + 1);
            // Simple swap
            int[] a = ar[index];
            ar[index] = ar[i];
            ar[i] = a;
        }
    }

    public int[] obtenerJugadadeString(String in, int[] t) {
        int[] j = new int[4];
        char[] c = in.toCharArray();

        j[1] = this.convnum(new char[]{c[0], c[1]});
        j[2] = this.convnum(new char[]{c[2], c[3]});

        j[0] = t[j[1]];

        if (c.length > 4) {
            switch (c[4]) {
                case 'N':
                case 'n':
                    j[3] = j[0] < 0 ? KNIGHT : knight;
                    break;
                case 'B':
                case 'b':
                    j[3] = j[0] < 0 ? BISHOP : bishop;
                    break;
                case 'R':
                case 'r':
                    j[3] = j[0] < 0 ? ROOK : rook;
                    break;
                case 'Q':
                case 'q':
                    j[3] = j[0] < 0 ? QUEEN : queen;
                    break;
            }
        }

        return j;
    }

    public String obtenerNotacionFEN(int[] tablero) {

        stb.delete(0, stb.length());
        int i;
        int h = 0;
        int ficha;

        for (i = 0; i < 64; i++) {
            ficha = tablero[i];

            if (ficha == vacio) {
                h++;
            } else {
                if (h == 0) {
                    stb.append(devolverPieza(ficha));
                } else {
                    stb.append(h).append(devolverPieza(ficha));
                    h = 0;
                }
            }
        }

        return stb.toString();
    }

    private String devolverPieza(int ficha) {
        switch (ficha) {
            case PAWN:
                return sPAWN;
            case pawn:
                return spawn;
            case BISHOP:
                return sBISHOP;
            case bishop:
                return sbishop;
            case KNIGHT:
                return sKNIGHT;
            case knight:
                return sknight;
            case ROOK:
                return sROOK;
            case rook:
                return srook;
            case QUEEN:
                return sQUEEN;
            case queen:
                return squeen;
            default: //king
                return ficha == KING ? sKING : sking;
        }
    }

    public void poblarLinea(int pos, int[] j) {
        linea[pos] = j;
    }

    public void findeLinea(int limite, int fin) {
        linea[limite + 1][0] = fin;
    }

    public void mostrarLinea() {
        int[] j;
        int cab;

        for_linea:
        for (int i = 0; i < linea.length; i++) {
            j = linea[i];
            cab = j[0];
            switch (cab) {
                case TRUE:
                    System.out.println("true");
                    break for_linea;
                case XTRUE:
                    System.out.println("xtrue");
                    break for_linea;
                case FALSE:
                    System.out.println("false");
                    break for_linea;
                case XFALSE:
                    System.out.println("xfalse");
                    break for_linea;
                default:
                    System.out.print(this.imprimirJugada(j) + ",");
            }
        }
    }

    public int[][] ordenarCapturas(int[][] capturas, int[] amenazas) {
        int size = capturas[0][0];
        int[][] capturasOrdenadas = new int[size][4];

        if (size < 3) {
            for (int i = 0; i < size; i++) {
                this.copiarArrayJugada(capturasOrdenadas[i], capturas[i]);
            }
        } else {
            int[] nuevasJugadas = new int[size - 1];
            int[] j;
            int ficha;

            this.inicializaOrdenadoresCaptura();

            for (int i = 0; i < size - 1; i++) {
                j = capturas[i + 1];
                ficha = j[0];

                switch (ficha) {
                    case QUEEN:
                    case queen:
                        if (cc[0] == 0 && cc[1] == 50) {
                            nuevasJugadas[i] = cc[1]++;
                        } else if (this.siArrayContiene(amenazas, j[2])) {
                            nuevasJugadas[i] = cc[0]++;
                        } else {
                            nuevasJugadas[i] = cc[1]++;
                        }
                        break;
                    case BISHOP:
                    case bishop:
                        if (cc[2] == 100 && cc[3] == 150) {
                            nuevasJugadas[i] = cc[3]++;
                        } else if (this.siArrayContiene(amenazas, j[2])) {
                            nuevasJugadas[i] = cc[2]++;
                        } else {
                            nuevasJugadas[i] = cc[3]++;
                        }
                        break;
                    case ROOK:
                    case rook:
                        if (cc[4] == 200 && cc[5] == 250) {
                            nuevasJugadas[i] = cc[5]++;
                        } else if (this.siArrayContiene(amenazas, j[2])) {
                            nuevasJugadas[i] = cc[4]++;
                        } else {
                            nuevasJugadas[i] = cc[5]++;
                        }
                        break;
                    case PAWN:
                    case pawn:
                        if (cc[6] == 300 && cc[7] == 350) {
                            nuevasJugadas[i] = cc[7]++;
                        } else if (this.siArrayContiene(amenazas, j[2])) {
                            nuevasJugadas[i] = cc[6]++;
                        } else {
                            nuevasJugadas[i] = cc[7]++;
                        }
                        break;
                    case KNIGHT:
                    case knight:
                        if (cc[8] == 400 && cc[9] == 450) {
                            nuevasJugadas[i] = cc[9]++;
                        } else if (this.siArrayContiene(amenazas, j[2])) {
                            nuevasJugadas[i] = cc[8]++;
                        } else {
                            nuevasJugadas[i] = cc[9]++;
                        }
                        break;
                    case KING:
                    case king:
                        nuevasJugadas[i] = cc[10]++;
                        break;
                }
            }

            int _lim;
            int p, q;
            int c = 1;

            this.copiarArrayJugada(capturasOrdenadas[_cabeceraJugadas], capturas[_cabeceraJugadas]);

            for (p = 0; p < 550; p = p + 50) {
                _lim = cc[p / 50] - p;
                for (q = 0; q < _lim; q++) {
                    this.copiarArrayJugada(capturasOrdenadas[c++], capturas[this.obtenerIndiceJugadaXOrden(nuevasJugadas, p + q, size - 1) + 1]);
                }
            }
        }

        return capturasOrdenadas;
    }

    public int[][] ordenarJaque(int[][] jaques, int[] tablero, int jugador) {
        int size = jaques[0][0];
        int[][] jaquesOrdenados = new int[size][4];

        if (size < 3) {
            for (int i = 0; i < size; i++) {
                this.copiarArrayJugada(jaquesOrdenados[i], jaques[i]);
            }
        } else {
            int[] nuevoOrden = new int[size - 1];
            int[] j;
            int ficha;

            this.inicializaOrdenadoresJaque();

            for (int i = 0; i < size - 1; i++) {
                j = jaques[i + 1];
                ficha = j[0];

                switch (ficha) {
                    case QUEEN:
                    case queen:
                        nuevoOrden[i] = _cj[0]++;
                        break;
                    case BISHOP:
                    case bishop:
                        nuevoOrden[i] = _cj[1]++;
                        break;
                    case ROOK:
                    case rook:
                        nuevoOrden[i] = _cj[2]++;
                        break;
                    case PAWN:
                    case pawn:
                        nuevoOrden[i] = _cj[3]++;
                        break;
                    case KNIGHT:
                    case knight:
                        nuevoOrden[i] = _cj[4]++;
                        break;
                    case KING:
                    case king:
                        if (this.verificarOrdenRey(tablero, jugador, j[2])) {
                            nuevoOrden[i] = _cj[5]++;
                        } else {
                            nuevoOrden[i] = _cj[6]++;
                        }
                        break;
                }
            }
            int _lim;
            int p, q;
            int c = 1;

            this.copiarArrayJugada(jaquesOrdenados[_cabeceraJugadas], jaques[_cabeceraJugadas]);

            for (p = 0; p < 700; p = p + 100) {
                _lim = _cj[p / 100] - p;
                for (q = 0; q < _lim; q++) {
                    this.copiarArrayJugada(jaquesOrdenados[c++], jaques[this.obtenerIndiceJugadaXOrden(nuevoOrden, p + q, size - 1) + 1]);
                }
            }
        }

        return jaquesOrdenados;
    }

    private boolean verificarOrdenRey(int[] tablero, int jugador, int pos) {
        int val;

        if (jugador == white) {
            val = pos - 1;
            if (val >= 0 && val % 8 < 7 && tablero[val] < vacio) {
                return false;
            }
            val = pos + 1;
            if (val % 8 > 0 && tablero[val] < vacio) {
                return false;
            }
            val = pos - 7;
            if (val % 8 > 0 && tablero[val] < vacio) {
                return false;
            }
            val = pos + 7;
            if (val < 64 && val % 8 < 7 && tablero[val] < vacio) {
                return false;
            }
            val = pos - 8;
            if (val >= 0 && tablero[val] < vacio) {
                return false;
            }
            val = pos + 8;
            if (val < 64 && tablero[val] < vacio) {
                return false;
            }
            val = pos - 9;
            if (val >= 0 && val % 8 < 7 && tablero[val] < vacio) {
                return false;
            }
            val = pos + 9;
            if (val < 64 && val % 8 > 0 && tablero[val] < vacio) {
                return false;
            }
        } else {
            val = pos - 1;
            if (val >= 0 && val % 8 < 7 && tablero[val] > vacio) {
                return false;
            }
            val = pos + 1;
            if (val % 8 > 0 && tablero[val] > vacio) {
                return false;
            }
            val = pos - 7;
            if (val % 8 > 0 && tablero[val] > vacio) {
                return false;
            }
            val = pos + 7;
            if (val < 64 && val % 8 < 7 && tablero[val] > vacio) {
                return false;
            }
            val = pos - 8;
            if (val >= 0 && tablero[val] > vacio) {
                return false;
            }
            val = pos + 8;
            if (val < 64 && tablero[val] > vacio) {
                return false;
            }
            val = pos - 9;
            if (val >= 0 && val % 8 < 7 && tablero[val] > vacio) {
                return false;
            }
            val = pos + 9;
            if (val < 64 && val % 8 > 0 && tablero[val] > vacio) {
                return false;
            }
        }
        return true;
    }

    public int[][] ordenarJugadasLocal(int[][] jugadas, int[] tablero,
            int[] amenazas, int[] amenazasrival, int jugador, int pos_king) {

        int size = jugadas[0][0];
        int[][] ordenado = new int[size][4];

        if (size < 3) {
            for (int i = 0; i < size; i++) {
                this.copiarArrayJugada(ordenado[i], jugadas[i]);
            }
        } else {
            int[] nuevoOrden = new int[size - 1];
            int cnt = 0;
            int ficha, fin;
            int[] jug;
            this.inicializaOrdenadoresLocal();

            for (int k = 1; k < size; k++) {
                jug = jugadas[k];
                ficha = jug[0];
                fin = jug[2];

                switch (ficha) {
                    case QUEEN:
                    case queen:
                        if (this.siArrayContiene(amenazasrival, fin)) {
                            if (!this.siArrayContieneDoble(amenazas, fin)) {
                                nuevoOrden[cnt] = c0[0];
                                c0[0]++;
                            } else {
                                nuevoOrden[cnt] = cx[0];
                                cx[0]++;
                            }
                        } else {
                            if (this.verificarJaque(tablero, ficha, fin, pos_king)) {
                                nuevoOrden[cnt] = cj[0];
                                cj[0]++;
                            } else {
                                nuevoOrden[cnt] = cn[0];
                                cn[0]++;
                            }
                        }
                        break;
                    case BISHOP:
                    case bishop:
                        if (this.siArrayContiene(amenazasrival, fin)) {
                            if (!this.siArrayContieneDoble(amenazas, fin)) {
                                nuevoOrden[cnt] = c0[1];
                                c0[1]++;
                            } else {
                                nuevoOrden[cnt] = cx[1];
                                cx[1]++;
                            }
                        } else {
                            if (this.verificarJaque(tablero, ficha, fin, pos_king)) {
                                nuevoOrden[cnt] = cj[1];
                                cj[1]++;
                            } else {
                                nuevoOrden[cnt] = cn[1];
                                cn[1]++;
                            }
                        }
                        break;
                    case ROOK:
                    case rook:
                        if (this.siArrayContiene(amenazasrival, fin)) {
                            if (!this.siArrayContieneDoble(amenazas, fin)) {
                                nuevoOrden[cnt] = c0[2];
                                c0[2]++;
                            } else {
                                nuevoOrden[cnt] = cx[2];
                                cx[2]++;
                            }
                        } else {
                            if (this.verificarJaque(tablero, ficha, fin, pos_king)) {
                                nuevoOrden[cnt] = cj[2];
                                cj[2]++;
                            } else {
                                nuevoOrden[cnt] = cn[2];
                                cn[2]++;
                            }
                        }
                        break;
                    case PAWN:
                    case pawn:
                        if (this.siArrayContiene(amenazasrival, fin)) {
                            if (!this.siArrayContiene(amenazas, fin)) {
                                nuevoOrden[cnt] = c0[3];
                                c0[3]++;
                            } else {
                                nuevoOrden[cnt] = cx[3];
                                cx[3]++;
                            }
                        } else {
                            nuevoOrden[cnt] = cn[3];
                            cn[3]++;
                        }
                        break;
                    case KNIGHT:
                    case knight:
                        if (this.siArrayContiene(amenazasrival, fin)) {
                            if (!this.siArrayContieneDoble(amenazas, fin)) {
                                nuevoOrden[cnt] = c0[4];
                                c0[4]++;
                            } else {
                                nuevoOrden[cnt] = cx[4];
                                cx[4]++;
                            }
                        } else {
                            if (this.verificarJaque(tablero, ficha, fin, pos_king)) {
                                nuevoOrden[cnt] = cj[3];
                                cj[3]++;
                            } else {
                                nuevoOrden[cnt] = cn[4];
                                cn[4]++;
                            }
                        }
                        break;
                    case KING:
                    case king:
                        if (this.verificarOrdenRey(tablero, jugador, jug[2])) {
                            nuevoOrden[cnt] = ck[0];
                            ck[0]++;
                        } else {
                            nuevoOrden[cnt] = ck[1];
                            ck[1]++;
                        }
                        break;
                }
                cnt++;
            }//ffor

            int _lim;
            int i, j;

            cnt = 1;
            this.copiarArrayJugada(ordenado[_cabeceraJugadas], jugadas[_cabeceraJugadas]);

            for (i = 0; i < 100; i = i + 20) {
                _lim = c0[i / 20] - i;
                for (j = 0; j < _lim; j++) {
                    this.copiarArrayJugada(ordenado[cnt++], jugadas[this.obtenerIndiceJugadaXOrden(nuevoOrden, i + j, size) + 1]);
                }
            }

            for (i = 100; i < 200; i = i + 20) {
                _lim = cx[(i - 100) / 20] - i;
                for (j = 0; j < _lim; j++) {
                    this.copiarArrayJugada(ordenado[cnt++], jugadas[this.obtenerIndiceJugadaXOrden(nuevoOrden, i + j, size) + 1]);
                }
            }

            for (i = 200; i < 700; i = i + 100) {
                _lim = cn[(i - 200) / 100] - i;
                for (j = 0; j < _lim; j++) {
                    this.copiarArrayJugada(ordenado[cnt++], jugadas[this.obtenerIndiceJugadaXOrden(nuevoOrden, i + j, size) + 1]);
                }
            }

            for (i = 700; i < 800; i = i + 50) {
                _lim = ck[(i - 700) / 50] - i;
                for (j = 0; j < _lim; j++) {
                    this.copiarArrayJugada(ordenado[cnt++], jugadas[this.obtenerIndiceJugadaXOrden(nuevoOrden, i + j, size) + 1]);
                }
            }

            for (i = 800; i < 880; i = i + 20) {
                _lim = cj[(i - 800) / 20] - i;
                for (j = 0; j < _lim; j++) {
                    this.copiarArrayJugada(ordenado[cnt++], jugadas[this.obtenerIndiceJugadaXOrden(nuevoOrden, i + j, size) + 1]);
                }
            }
        }

        return ordenado;
    }

    private int obtenerIndiceJugadaXOrden(int[] nuevoOrden, int pos, int l) {
        for (int i = 0; i < l; i++) {
            if (nuevoOrden[i] == pos) {
                return i;
            }
        }
        return -1;
    }

    private boolean siArrayContieneDoble(int[] amenazas, int val) {
        int cnt = 0;
        for (int j = 1; j < amenazas[0]; j++) {
            if (amenazas[j] == val) {
                if (cnt == 1) {
                    return true;
                } else {
                    cnt++;
                }
            }
        }
        return false;
    }

    public boolean ingresarJugadayVerificarEnroques(int[] tablero, boolean[] enroques, int[] jugada, boolean isWhite) {

        int ficha = jugada[0];
        int ini = jugada[1];
        int fin = jugada[2];
        int prom = jugada.length > 3 ? jugada[3] : 0;

        if (ficha == pawn || ficha == PAWN) {
            if (fin > ini) {
                if (ini >= 32 && ini <= 39 && ini + 8 != fin && tablero[fin] == vacio) {
                    tablero[(fin - 8)] = vacio;
                }
            } else if (ini >= 24 && ini <= 31 && ini - 8 != fin && tablero[fin] == vacio) {
                tablero[(fin + 8)] = vacio;
            }
        } else if ((ficha == king || ficha == KING) && (ini == 4 || ini == 60)) {
            if (enroques[isWhite ? 0 : 2] || enroques[isWhite ? 1 : 3]) {
                enroques[isWhite ? 0 : 2] = false;
                enroques[isWhite ? 1 : 3] = false;
            }
            switch (fin) {
                case 2:
                    tablero[3] = ROOK;
                    tablero[0] = vacio;
                    break;
                case 6:
                    tablero[5] = ROOK;
                    tablero[7] = vacio;
                    break;
                case 58:
                    tablero[59] = rook;
                    tablero[56] = vacio;
                    break;
                case 62:
                    tablero[61] = rook;
                    tablero[63] = vacio;
                    break;
            }
        } else if (ficha == rook || ficha == ROOK) {
            if (enroques[isWhite ? 0 : 2] || enroques[isWhite ? 1 : 3]) {
                switch (ini) {
                    case 0:
                    case 56:
                        enroques[isWhite ? 1 : 3] = false;
                        break;
                    case 7:
                    case 63:
                        enroques[isWhite ? 0 : 2] = false;
                        break;
                }
            }
        }

        if (tablero[fin] == rook || tablero[fin] == ROOK) {
            if (enroques[!isWhite ? 0 : 2] || enroques[!isWhite ? 1 : 3]) {
                switch (ini) {
                    case 0:
                    case 56:
                        enroques[!isWhite ? 1 : 3] = false;
                        break;
                    case 7:
                    case 63:
                        enroques[!isWhite ? 0 : 2] = false;
                        break;
                }
            }
        }

        tablero[fin] = (prom != 0 ? prom : tablero[ini]);
        tablero[ini] = vacio;

        int cnt = 0;
        if (isWhite) {
            for (int i = 0; i < 64; i++) {
                if (tablero[i] > 0) {
                    if ((cnt = cnt + 1) > 1) {
                        break;
                    }
                }
            }
        } else {
            for (int i = 0; i < 64; i++) {
                if (tablero[i] < 0) {
                    if ((cnt = cnt + 1) > 1) {
                        break;
                    }
                }
            }
        }

        return cnt == 1 ? true : false;
    }

    public int[][] poblarcache(int[][] temp) {
        int cab;
        int c = 1;
        int[] j;

        for_linea:
        for (int i = 0; i < linea.length; i++) {
            j = linea[i];
            cab = j[0];
            switch (cab) {
                case TRUE:
                case XTRUE:
                case FALSE:
                case XFALSE:
                    break for_linea;
                default:
                    this.copiarArrayJugada(temp[c++], j);
            }
        }


        temp[0][0] = c;
        temp[0][1] = 1;

        return temp;
    }

    public String mostrarCache(int[][][] cachememory) {
        StringBuilder sb = new StringBuilder();
        int[][] l;
        int cnt = 1;

        for (int k = 1; k < cachememory[0][0][0]; k++) {
            l = cachememory[k];
            sb.append(cnt++).append(")");
            for (int i = 1; i < l[0][0]; i++) {
                sb.append(this.imprimirJugada(l[i])).append(",");
            }
            sb.append("\n");
        }

        return sb.toString();
    }

    public boolean verificarJaque(int[] tablero, int ficha, int pos,
            int pos_king) {

        switch (ficha) {
            case QUEEN:
            case queen:
                if (this.verificarJaqueDiagonal(tablero, pos, pos_king)) {
                    return true;
                }
                if (this.verificarJaqueHorizontalVertical(tablero, pos, pos_king)) {
                    return true;
                }
                break;
            case BISHOP:
            case bishop:
                if (this.verificarJaqueDiagonal(tablero, pos, pos_king)) {
                    return true;
                }
                break;
            case ROOK:
            case rook:
                if (this.verificarJaqueHorizontalVertical(tablero, pos, pos_king)) {
                    return true;
                }
                break;
            case KNIGHT:
            case knight:
                // +6 -6
                if ((pos < 56 && pos % 8 > 1) && pos + 6 == pos_king) {
                    return true;
                }
                if (pos > 7 && pos % 8 < 6 && pos - 6 == pos_king) {
                    return true;
                }
                // +10 -10
                if (pos < 56 && pos % 8 < 6 && pos + 10 == pos_king) {
                    return true;
                }
                if (pos > 7 && pos % 8 > 1 && pos - 10 == pos_king) {
                    return true;
                }
                // +15 -15
                if (pos < 48 && pos % 8 > 0 && pos + 15 == pos_king) {
                    return true;
                }
                if (pos > 15 && pos % 8 < 7 && pos - 15 == pos_king) {
                    return true;
                }
                // +17 -17
                if (pos < 48 && pos % 8 < 7 && pos + 17 == pos_king) {
                    return true;
                }
                if ((pos > 15 && pos % 8 > 0) && pos - 17 == pos_king) {
                    return true;
                }
                break;
        }

        return false;
    }

    private boolean verificarJaqueDiagonal(int[] tablero, int pos, int pos_king) {

        int factor = 1;
        int val;
        boolean a7 = true,
                b7 = true,
                a9 = true,
                b9 = true;
        do {
            if (a7) {
                val = pos - (7 * factor);
                if (val % 8 > 0) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        a7 = false;
                    }
                } else {
                    a7 = false;
                }
            }
            if (b7) {
                val = pos + (7 * factor);
                if (val < 64 && val % 8 < 7) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        b7 = false;
                    }
                } else {
                    b7 = false;
                }
            }
            if (a9) {
                val = pos - (9 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        a9 = false;
                    }
                } else {
                    a9 = false;
                }
            }
            if (b9) {
                val = pos + (9 * factor);
                if (val < 64 && val % 8 > 0) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        b9 = false;
                    }
                } else {
                    b9 = false;
                }
            }
            factor++;
        } while ((a7 || b7 || a9 || b9) && factor < 8);

        return false;
    }

    private boolean verificarJaqueHorizontalVertical(int[] tablero, int pos, int pos_king) {

        int factor = 1;
        int val;
        boolean a1 = true,
                b1 = true,
                a8 = true,
                b8 = true;
        do {
            if (a1) {
                val = pos - (1 * factor);
                if (val >= 0 && val % 8 < 7) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        a1 = false;
                    }
                } else {
                    a1 = false;
                }
            }
            if (b1) {
                val = pos + (1 * factor);
                if (val % 8 > 0) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        b1 = false;
                    }
                } else {
                    b1 = false;
                }
            }
            if (a8) {
                val = pos - (8 * factor);
                if (val >= 0) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        a8 = false;
                    }
                } else {
                    a8 = false;
                }
            }
            if (b8) {
                val = pos + (8 * factor);
                if (val < 64) {
                    if (val == pos_king) {
                        return true;
                    } else if (tablero[val] != vacio) {
                        b8 = false;
                    }
                } else {
                    b8 = false;
                }
            }
            factor++;
        } while ((a1 || b1 || a8 || b8) && factor < 8);

        return false;
    }

    public int[] buscarIndiceAmenazaEscondida(int[][] escondidas, int idx) {
        int temp;

        for (int i = 1; i < escondidas[0][indiceMovimiento]; i++) {
            temp = escondidas[i][indiceMovimiento];
            if (temp == idx) {
                return escondidas[i];
            }
        }
        return null;
    }

    public void iniciarCabeceraJugada(int[] j) {
        j[0] = 1;
        j[1] = 0;
        j[2] = 0;
        j[3] = 0;
    }

    private void copiarArrayJugada(int[] dest, int[] src) {
        dest[0] = src[0];
        dest[1] = src[1];
        dest[2] = src[2];
        dest[3] = src[3];
    }

    public boolean compararTableros(int[] t1, int t2[]) {

        int n = 64;
        int i = 0;
        while (n-- != 0) {
            if (t1[i] != t2[i]) {
                return false;
            }
            i++;
        }
        return true;
    }
}
